package com.nebula.service.Impl;

import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alipay.api.AlipayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.nebula.common.Const;
import com.nebula.common.ServerResponse;
import com.nebula.mapper.OrderMapper;
import com.nebula.mapper.PayInfoMapper;
import com.nebula.pojo.Order;
import com.nebula.pojo.PayInfo;
import com.nebula.service.IOrderService;
import com.nebula.util.BigDecimalUtil;
import com.nebula.util.DateTimeUtil;
import com.nebula.util.IDUtil;
import com.nebula.vo.MyOrderVo;


@Service("orderService")
public class OrderServiceImpl implements IOrderService {
	private static  AlipayTradeService tradeService;
    static {

        /** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
         *  Configs会读取classpath下的zfbinfo.properties文件配置信息，如果找不到该文件则确认该文件是否在classpath目录
         */
        Configs.init("zfbinfo.properties");

        /** 使用Configs提供的默认参数
         *  AlipayTradeService可以使用单例或者为静态成员对象，不需要反复new
         */
        tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
    }
	
	private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
	
	@Autowired
	private OrderMapper orderMapper;
	@Autowired
	private PayInfoMapper payInfoMapper;
	
	public ServerResponse createOrder(String username,Integer groupId,BigDecimal payment,Integer paymentType){
		Long orderNo = IDUtil.getItemId();
		Order order = new Order();
		order.setOrderNo(orderNo);
		order.setUsername(username);
		order.setGroupid(groupId);
		order.setStatus(10);
		order.setPayment(payment);
		order.setPaymentType(paymentType);
		
		int resultCount = orderMapper.insert(order);
		if(resultCount > 0){
			return ServerResponse.createBySuccess(orderNo);
		}
		return ServerResponse.createByError();
	}
	
	
	public ServerResponse pay(Long orderNo,String username,String path,String type){
		Map<String, String> resultMap = Maps.newHashMap();
		
		Order order = orderMapper.selectByUsernameAndOrderNo(username, orderNo);
		if(order == null){
			return ServerResponse.createByErrorMessage("用户没有该订单");
		}
		resultMap.put("orderNo", String.valueOf(order.getOrderNo()));
		
		// (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
        // 需保证商户系统端不能重复，建议通过数据库sequence生成，
        String outTradeNo = order.getOrderNo().toString();

        // (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
        String subject = new StringBuilder().append("大岭山中学网盘会员购买:").append(type).toString();

        // (必填) 订单总金额，单位为元，不能超过1亿元
        // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
        String totalAmount = order.getPayment().toString();

        // (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
        // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
        String undiscountableAmount = "0";

        // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
        // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        String sellerId = "";

        // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
        String body = new StringBuilder().append("订单").append(outTradeNo).append("共支付").append(totalAmount).append("元").toString();

        // 商户操作员编号，添加此参数可以为商户操作员做销售统计
        String operatorId = "test_operator_id";

        // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
        String storeId = "test_store_id";

        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId("2088100200300400500");

        // 支付超时，定义为120分钟
        String timeoutExpress = "120m";

        // 商品明细列表，需填写购买商品详细信息，
        List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();
        // 创建一个商品信息，参数含义分别为商品id（使用国标）、名称、单价（单位为分）、数量，如果需要添加商品类别，详见GoodsDetail
        GoodsDetail goods = GoodsDetail.newInstance(order.getGroupid().toString(), type, 
        		BigDecimalUtil.mul(order.getPayment().doubleValue(),new Double(100).doubleValue()).longValue(), 1);
        // 创建好一个商品后添加至商品明细列表
        goodsDetailList.add(goods);

        // 创建扫码支付请求builder，设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
            .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
            .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
            .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
            .setTimeoutExpress(timeoutExpress)
            .setNotifyUrl("http://privatecloud.s1.natapp.cc/nebula/order/alipay_callback.action")//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
            .setGoodsDetailList(goodsDetailList);
        
        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
            	logger.info("支付宝预下单成功: )");

                AlipayTradePrecreateResponse response = result.getResponse();
                dumpResponse(response);

                File folder = new File(path);
                if(!folder.exists()){
                	folder.setWritable(true);
                	folder.mkdirs();
                }
                
                // 需要修改为运行机器上的路径
                String qrPath = String.format(path + "/qr-%s.png",response.getOutTradeNo());
                String qrUrl = String.format("/nebula/qrCode/qr-%s.png",response.getOutTradeNo());
                ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);
                logger.info("qrPath:" + qrPath);
                
                resultMap.put("qrUrl", qrUrl);
                return ServerResponse.createBySuccess(resultMap);
            case FAILED:
            	logger.error("支付宝预下单失败!!!");
                return ServerResponse.createByErrorMessage("支付宝预下单失败!!!");

            case UNKNOWN:
            	logger.error("系统异常，预下单状态未知!!!");
            	return ServerResponse.createByErrorMessage("系统异常，预下单状态未知!!!");
            default:
            	logger.error("不支持的交易状态，交易返回异常!!!");
            	return ServerResponse.createByErrorMessage("不支持的交易状态，交易返回异常!!!");
        }
	}
	
	public ServerResponse aliCallback(Map<String, String> params){
		Long orderNo = Long.parseLong(params.get("out_trade_no"));
		String tradeNo = params.get("trade_no");
		String tradeStatus = params.get("trade_status");
		Order order = orderMapper.selectByOrderNo(orderNo);
		if(order == null){
			return ServerResponse.createByErrorMessage("非本系统的订单,回调忽略");
		}
		if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
			return ServerResponse.createBySuccess("支付宝重复调用");
		}
		if(Const.AlipayCallback.TRADE_STATUS_TRADE_SUCCESS.equals(tradeStatus)){
			order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment")));
			order.setStatus(Const.OrderStatusEnum.PAID.getCode());
			orderMapper.updateByPrimaryKeySelective(order);
		}
		
		PayInfo payInfo = new PayInfo();
		payInfo.setUsername(order.getUsername());
		payInfo.setOrderNo(order.getOrderNo());
		payInfo.setPayPlatform(Const.PayPlatformEnum.ALIPAY.getCode());
		payInfo.setPlatformNumber(tradeNo);
		payInfo.setPlatformStatus(tradeStatus);
		
		payInfoMapper.insert(payInfo);
		
		return ServerResponse.createBySuccess();
	}
	
	public ServerResponse queryOrderPayStatus(String username,Long orderNo){
		Order order = orderMapper.selectByUsernameAndOrderNo(username, orderNo);
		if(order == null){
			return ServerResponse.createByErrorMessage("用户没有该订单");
		}
		if(order.getStatus() >= Const.OrderStatusEnum.PAID.getCode()){
			return ServerResponse.createBySuccess();
		}
		return ServerResponse.createByError();
	}
	
	public ServerResponse queryOrderDetail(String username){
		List<Order> orderList = orderMapper.selectOrderInfoByUsername(username);
		List<MyOrderVo> myOrderVos = Lists.newArrayList();
		for(Order order : orderList){
			MyOrderVo myOrderVo = assembleMyOrderVo(order);
			myOrderVos.add(myOrderVo);
		}
		return ServerResponse.createBySuccess(myOrderVos);
	}
	
	private MyOrderVo assembleMyOrderVo(Order order){
		MyOrderVo myOrderVo = new MyOrderVo();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		myOrderVo.setOrderNo(order.getOrderNo());
		myOrderVo.setCreateTime(sdf.format(order.getCreateTime()));
		myOrderVo.setPayment(order.getPayment());
		if(order.getPaymentType().equals(1)){
			myOrderVo.setPaymentType("在线支付");
		}
		
		if(order.getPayInfo() == null){
			myOrderVo.setPayPlatform("");
			myOrderVo.setPlatformNumber("");
		}else{
			if(order.getPayInfo().getPayPlatform().equals(1)){
				myOrderVo.setPayPlatform("支付宝");
			}else if(order.getPayInfo().getPayPlatform().equals(2)){
				myOrderVo.setPayPlatform("微信");
			}
			myOrderVo.setPlatformNumber(order.getPayInfo().getPlatformNumber());
		}
		
		if(order.getStatus().equals(0)){
			myOrderVo.setStatus("已取消");
		}else if(order.getStatus().equals(10)){
			myOrderVo.setStatus("未付款");
		}else if(order.getStatus() >= 20){
			myOrderVo.setStatus("已付款");
		}
		
		myOrderVo.setTradeName(order.getUserGroups().getGroupname());
		
		return myOrderVo;
	}
	
	// 简单打印应答
    private void dumpResponse(AlipayResponse response) {
        if (response != null) {
        	logger.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
            	logger.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                    response.getSubMsg()));
            }
            logger.info("body:" + response.getBody());
        }
    }
}
